Avoid running `build.rs` too often.
authorEric Huss <eric@huss.org>
Fri, 20 Apr 2018 20:20:38 +0000 (13:20 -0700)
committerEric Huss <eric@huss.org>
Fri, 27 Apr 2018 20:42:30 +0000 (13:42 -0700)
src/cargo/core/compiler/context/unit_dependencies.rs
src/cargo/core/compiler/custom_build.rs
src/cargo/core/profiles.rs
src/cargo/ops/cargo_clean.rs

index 0e1c9c078025d250b29fe20b54454535def1098c..b329de85aa973cadacec0fa4aa56a8ca93ad2f6b 100644 (file)
@@ -132,7 +132,7 @@ fn compute_deps<'a, 'b, 'cfg>(
     if unit.target.is_custom_build() {
         return Ok(ret);
     }
-    ret.extend(dep_build_script(unit));
+    ret.extend(dep_build_script(cx, unit));
 
     // If this target is a binary, test, example, etc, then it depends on
     // the library of the same package. The call to `resolve.deps` above
@@ -180,7 +180,7 @@ fn compute_deps_custom_build<'a, 'cfg>(
             if !unit.target.linkable() || unit.pkg.manifest().links().is_none() {
                 return None;
             }
-            dep_build_script(unit)
+            dep_build_script(cx, unit)
         })
         .chain(Some((
             new_unit(
@@ -250,7 +250,7 @@ fn compute_deps_doc<'a, 'cfg>(
     }
 
     // Be sure to build/run the build script for documented libraries as
-    ret.extend(dep_build_script(unit));
+    ret.extend(dep_build_script(cx, unit));
 
     // If we document a binary, we need the library available
     if unit.target.is_bin() {
@@ -278,7 +278,7 @@ fn maybe_lib<'a>(
 /// script itself doesn't have any dependencies, so even in that case a unit
 /// of work is still returned. `None` is only returned if the package has no
 /// build script.
-fn dep_build_script<'a>(unit: &Unit<'a>) -> Option<(Unit<'a>, ProfileFor)> {
+fn dep_build_script<'a>(cx: &Context, unit: &Unit<'a>) -> Option<(Unit<'a>, ProfileFor)> {
     unit.pkg
         .targets()
         .iter()
@@ -286,13 +286,11 @@ fn dep_build_script<'a>(unit: &Unit<'a>) -> Option<(Unit<'a>, ProfileFor)> {
         .map(|t| {
             // The profile stored in the Unit is the profile for the thing
             // the custom build script is running for.
-            // TODO: Fix this for different profiles that don't affect the
-            // build.rs environment variables.
             (
                 Unit {
                     pkg: unit.pkg,
                     target: t,
-                    profile: unit.profile,
+                    profile: cx.profiles.get_profile_run_custom_build(&unit.profile),
                     kind: unit.kind,
                     mode: CompileMode::RunCustomBuild,
                 },
index 96638bf0f7531e49c6b3aa532e23615df4e6d3b4..02fd48de03118f1d645aa60fd383867ca000ff63 100644 (file)
@@ -118,6 +118,9 @@ fn build_work<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) -> CargoRes
     // environment variables. Note that the profile-related environment
     // variables are not set with this the build script's profile but rather the
     // package's library profile.
+    // NOTE: If you add any profile flags, be sure to update
+    // `Profiles::get_profile_run_custom_build` so that those flags get
+    // carried over.
     let to_exec = to_exec.into_os_string();
     let mut cmd = cx.compilation.host_process(to_exec, unit.pkg)?;
     cmd.env("OUT_DIR", &build_output)
index c76be468c276a9896363113d6c7831744e1760cd..ac3651fe0bfcd3b53db051dc70678811fe74fe12 100644 (file)
@@ -90,6 +90,18 @@ impl Profiles {
         profile
     }
 
+    /// The profile for *running* a `build.rs` script is only used for setting
+    /// a few environment variables.  To ensure proper de-duplication of the
+    /// running `Unit`, this uses a stripped-down profile (so that unrelated
+    /// profile flags don't cause `build.rs` to needlessly run multiple
+    /// times).
+    pub fn get_profile_run_custom_build(&self, for_unit_profile: &Profile) -> Profile {
+        let mut result = Profile::default();
+        result.debuginfo = for_unit_profile.debuginfo;
+        result.opt_level = for_unit_profile.opt_level;
+        result
+    }
+
     /// This returns a generic base profile. This is currently used for the
     /// `[Finished]` line.  It is not entirely accurate, since it doesn't
     /// select for the package that was actually built.
index 21e195212e82f425e8d8676002090e1fa93310c1..3c0321c42ff38bbcea2bbd052c3006be5d67cf51 100644 (file)
@@ -49,13 +49,23 @@ pub fn clean(ws: &Workspace, opts: &CleanOptions) -> CargoResult<()> {
             for kind in [Kind::Host, Kind::Target].iter() {
                 for mode in CompileMode::all_modes() {
                     for profile_for in ProfileFor::all_values() {
-                        let profile = profiles.get_profile(
-                            &pkg.name(),
-                            ws.is_member(pkg),
-                            *profile_for,
-                            *mode,
-                            opts.release,
-                        );
+                        let profile = if mode.is_run_custom_build() {
+                            profiles.get_profile_run_custom_build(&profiles.get_profile(
+                                &pkg.name(),
+                                ws.is_member(pkg),
+                                *profile_for,
+                                CompileMode::Build,
+                                opts.release,
+                            ))
+                        } else {
+                            profiles.get_profile(
+                                &pkg.name(),
+                                ws.is_member(pkg),
+                                *profile_for,
+                                *mode,
+                                opts.release,
+                            )
+                        };
                         units.push(Unit {
                             pkg,
                             target,